﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;

namespace ElectronicCommerce.Framework.Web.Mvc.WebForm
{
    public abstract class CustomViewMasterPageBase<TCustomViewPage,
        TCustomContext,
        TViewMasterPageAliasType> : MasterPage
        where TCustomViewPage : CustomViewPageBase<TCustomContext>
        where TCustomContext : CustomContextBase
        where TViewMasterPageAliasType : struct
    {
        public TCustomViewPage ViewPage
        {
            get
            {
                return Page as TCustomViewPage;
            }
        }

        public TCustomContext CustomContext
        {
            get
            {
                return ViewPage.CustomContext;
            }
        }

        private string _relativePath = null;
        protected string RelativePath
        {
            get
            {
                if (_relativePath == null)
                {
                    if (!string.IsNullOrEmpty(CustomContext.Request.Path))
                    {
                        _relativePath = CustomContext.Request.Path.Replace("/", ".").Trim('.');
                    }
                    if (!string.IsNullOrEmpty(_relativePath))
                    {
                        _relativePath = " (" + _relativePath + ")";
                    }
                }
                return _relativePath;
            }
        }

        protected abstract string TitlePrefix { get; }
        protected abstract string TitlePostfix { get; }
        protected abstract string DefaultTitle { get; }

        protected abstract string DefaultDescription { get; }

        protected abstract string KeywordsPrefix { get; }
        protected abstract string DefaultKeywords { get; }

        private string _title = null;
        protected string Title
        {
            get
            {
                if (_title == null)
                {
                    if (string.IsNullOrEmpty(ViewPage.Metadata.Title))
                    {
                        if (!string.IsNullOrEmpty(DefaultTitle))
                        {
                            _title += DefaultTitle;
                        }
                    }
                    else
                    {
                        _title += ViewPage.Metadata.Title;

                        if (!string.IsNullOrEmpty(TitlePrefix))
                        {
                            if (!string.IsNullOrEmpty(_title))
                            {
                                _title = " / " + _title;
                            }

                            _title = TitlePrefix + _title;
                        }

                        if (!string.IsNullOrEmpty(TitlePostfix))
                        {
                            _title += " - " + TitlePostfix;
                        }
                    }

                    if (ViewPage.AvoidDuplicatedTitle)
                    {
                        _title += RelativePath;
                    }
                }
                return _title;
            }
        }

        private string _keywords = null;
        protected string Keywords
        {
            get
            {
                if (_keywords == null)
                {
                    if (!string.IsNullOrEmpty(KeywordsPrefix))
                    {
                        _keywords += KeywordsPrefix + ", ";
                    }

                    if (string.IsNullOrEmpty(ViewPage.Metadata.Keywords))
                    {
                        _keywords += DefaultKeywords;
                    }
                    else
                    {
                        _keywords += ViewPage.Metadata.Keywords;
                    }
                    _keywords = _keywords.ToLower();
                }
                return _keywords;
            }
        }

        private string _description = null;
        protected string Description
        {
            get
            {
                if (_description == null)
                {
                    if (string.IsNullOrEmpty(ViewPage.Metadata.Description))
                    {
                        _description = DefaultDescription;
                    }
                    else
                    {
                        _description = ViewPage.Metadata.Description;

                        if (ViewPage.AvoidDuplicatedTitle)
                        {
                            _description += RelativePath;
                        }
                    }
                }
                return _description;
            }
        }

        protected string CanonicalLink
        {
            get
            {
                return GetMetadataLink(ViewPage.Metadata.CanonicalLink);
            }
        }

        private string _style = string.Empty;
        protected string InlineStyles
        {
            get
            {
                if (string.IsNullOrEmpty(_style) && ViewPage.Metadata.InlineStyles.Count > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (string s in ViewPage.Metadata.InlineStyles)
                    {
                        sb.Append(s.Trim());
                    }

                    _style = sb.ToString().Trim();

                    if (!string.IsNullOrEmpty(_style))
                    {
                        return string.Format(@"<style type=""text/css"">{0}</style>", _style);
                    }
                }
                return string.Empty;
            }
        }

        private string _csslinks = null;
        protected string CssLinks
        {
            get
            {
                if (_csslinks == null)
                {
                    _csslinks = GetLinks(ViewPage.Metadata.Css);
                }
                return _csslinks;
            }
        }

        private string _rsslinks = null;
        protected string RssLinks
        {
            get
            {
                if (_rsslinks == null)
                {
                    _rsslinks = GetLinks(ViewPage.Metadata.Rss);
                }
                return _rsslinks;
            }
        }

        private string _inlineScript = string.Empty;
        protected string InlineScripts
        {
            get
            {
                if (string.IsNullOrEmpty(_inlineScript) && ViewPage.Metadata.InlineScripts.Count > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (string s in ViewPage.Metadata.InlineScripts)
                    {
                        sb.Append(s.Trim());
                    }

                    _inlineScript = sb.ToString().Trim();

                    if (!string.IsNullOrEmpty(_inlineScript))
                    {
                        return string.Format(@"<script type=""text/javascript"">{0}</script>", _inlineScript);
                    }
                }
                return string.Empty;
            }
        }

        private string _headScriptLinks = null;
        protected string HeadScripts
        {
            get
            {
                if (_headScriptLinks == null)
                {
                    _headScriptLinks = GetScriptLinks(ViewPage.Metadata.Scripts.FindAll(new Predicate<MetadataScriptLink>(delegate(MetadataScriptLink script)
                    {
                        return script.InHtmlHead;
                    })));
                }
                return _headScriptLinks;
            }
        }

        private string _footScriptLinks = null;
        protected string FootScripts
        {
            get
            {
                if (_footScriptLinks == null)
                {
                    _footScriptLinks = GetScriptLinks(ViewPage.Metadata.Scripts.FindAll(new Predicate<MetadataScriptLink>(delegate(MetadataScriptLink script)
                    {
                        return !script.InHtmlHead;
                    })));
                }
                return _footScriptLinks;
            }
        }

        private string GetScriptLinks(List<MetadataScriptLink> scripts)
        {
            StringBuilder sb = new StringBuilder();
            int i = 0;
            foreach (MetadataScriptLink script in scripts)
            {
                if (i > 0)
                {
                    sb.Append("\t");
                }
                sb.AppendLine(GetMetadataScriptLink(script));
                i += 1;
            }
            return sb.ToString();
        }

        private string GetLinks(List<MetadataLink> links)
        {
            StringBuilder sb = new StringBuilder();
            int i = 0;
            foreach (MetadataLink link in links)
            {
                if (i > 0)
                {
                    sb.Append("\t");
                }
                sb.AppendLine(GetMetadataLink(link));
                i += 1;
            }
            return sb.ToString();
        }

        public string MetadataNoIndex
        {
            get
            {
                if (ViewPage.Metadata.NoIndex)
                {
                    return "<meta name=\"robots\" content=\"noindex\" />";
                }
                return string.Empty;
            }
        }

        public string MetadataContentType
        {
            get
            {
                if (string.IsNullOrEmpty(ViewPage.Metadata.ContentType))
                {
                    ViewPage.Metadata.ContentType = CustomContext.Response.Charset;
                }

                return string.Format("<meta http-equiv=\"Content-Type\" content=\"text/html; charset={0}\" />", ViewPage.Metadata.ContentType);
            }
        }

        protected string GetMetadataCssLink(Enum cssAlias)
        {
            if (cssAlias != null)
            {
                return GetMetadataLink(new MetadataLink()
                {
                    Type = "text/css",
                    Rel = "stylesheet",
                    Href = ViewPage.Resource.BuildCss(cssAlias),
                    Media = "all"
                });
            }
            return string.Empty;
        }

        protected string GetMetadataLink(MetadataLink link)
        {
            StringBuilder sb = new StringBuilder();
            if (link != null)
            {
                sb.Append("<link");
                if (!string.IsNullOrEmpty(link.Rel))
                {
                    sb.AppendFormat(" rel=\"{0}\"", HttpUtility.HtmlEncode(link.Rel));
                }
                if (!string.IsNullOrEmpty(link.Type))
                {
                    sb.AppendFormat(" type=\"{0}\"", HttpUtility.HtmlEncode(link.Type));
                }
                if (!string.IsNullOrEmpty(link.Title))
                {
                    sb.AppendFormat(" title=\"{0}\"", HttpUtility.HtmlEncode(link.Title));
                }
                if (!string.IsNullOrEmpty(link.Href))
                {
                    sb.AppendFormat(" href=\"{0}\"", HttpUtility.HtmlEncode(link.Href));
                }
                if (!string.IsNullOrEmpty(link.Media))
                {
                    sb.AppendFormat(" media=\"{0}\"", HttpUtility.HtmlEncode(link.Media));
                }
                sb.Append(" />");
            }
            return sb.ToString();
        }

        private string GetMetadataScriptLink(MetadataScriptLink script)
        {
            StringBuilder sb = new StringBuilder();
            if (script != null)
            {
                sb.Append("<script");
                if (!string.IsNullOrEmpty(script.Type))
                {
                    sb.AppendFormat(" type=\"{0}\"", HttpUtility.HtmlEncode(script.Type));
                }
                if (!string.IsNullOrEmpty(script.Src))
                {
                    sb.AppendFormat(" src=\"{0}\"", HttpUtility.HtmlEncode(script.Src));
                }
                sb.Append("></script>");
            }
            return sb.ToString();
        }

        public abstract TViewMasterPageAliasType ViewMasterPageAlias { get; }
    }
}
